/**************************************************************************************************
	$Header: /pub/cvsroot/mydns/src/mydns/rr.c,v 1.8 2002/07/29 04:42:51 bboy Exp $
	rr.c: Routines for managing resource records.

	Copyright (C) 2002  Don Moore <bboy@bboy.net>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at Your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
**************************************************************************************************/

#include "named.h"


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	RRLIST_FREE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
rrlist_free(list)
	RRLIST *list;
{
	if (list)
	{
		register RR *p, *tmp;

		for (p = list->head; p; p = tmp)
		{
			tmp = p->next;
			switch (p->rrtype)
			{
				case DNS_RRTYPE_SOA:
					mydns_soa_free((MYDNS_SOA *)p->rr);
					break;
				case DNS_RRTYPE_RR:
					mydns_rr_free((MYDNS_RR *)p->rr);
					break;
				case DNS_RRTYPE_PTR:
					mydns_ptr_free((MYDNS_PTR *)p->rr);
					break;
			}
			free(p);
		}
		list->size = 0;
		list->addresses = list->highest_addr_aux = 0;
		list->head = list->tail = NULL;
	}
}
/*--- rrlist_free() -----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	RRDUP
	Returns nonzero if the resource record specified is duplicated in the provided list.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static int
rrdup(RRLIST *list, dns_rrtype_t rrtype, u_int32_t id)
{
	register RR *r;

	if (list)
		for (r = list->head; r; r = r->next)
			if (r->rrtype == rrtype && r->id == id)
				return (1);
	return (0);
}
/*--- rrdup() -----------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	RRLIST_ADD
	Adds a resource record to the section specified.
	The function will make a copy of `rr', so the caller should free their copy if desired.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
rrlist_add(t, ds, rrtype, rr, name)
	TASK *t;						/* The task to add a record to */
	datasection_t ds;			/* Add `rr' to this data section */
	dns_rrtype_t rrtype;		/* The type of resource record being added */
	void *rr;					/* The resource record to add */
	u_char *name;				/* Name to send with reply */
{
	RRLIST *list = NULL;
	RR *new;
	u_int32_t id = 0;

#if DEBUG
	{
		char *sec = ((ds == ANSWER) ? "ANSWER" : ((ds == AUTHORITY) ? "AUTHORITY" : "ADDITIONAL"));
		switch (rrtype)
		{
			case DNS_RRTYPE_SOA:
				{
					MYDNS_SOA *soa = (MYDNS_SOA *)rr;
					Debug(_("%s: RRLIST_ADD: %s %u (%s) (`%s')"), desctask(t),
							sec, soa->id, soa->origin, name);
				}
				break;
			case DNS_RRTYPE_PTR:
				{
					MYDNS_PTR *ptr = (MYDNS_PTR *)rr;
					Debug(_("%s: RRLIST_ADD: %s %u (%s) (`%s')"), desctask(t),
							sec, ptr->id, ptr->name, name);
				}
				break;
			case DNS_RRTYPE_RR:
				{
					MYDNS_RR *r = (MYDNS_RR *)rr;
					Debug(_("%s: RRLIST_ADD: %s %u (%s,%s,%s) (`%s')"), desctask(t),
							sec, r->id,
							(u_char *)(strlen(r->name) ? r->name : (u_char *)"@"),
							mydns_qtype_str(r->type), r->data, name);
				}
				break;
		}
	}
#endif

	switch (ds)
	{
		case ANSWER:
			list = &t->an;
			break;
		case AUTHORITY:
			list = &t->ns;
			break;
		case ADDITIONAL:
			list = &t->ar;
			break;
	}

	/* Check to make sure this isn't a duplicate */
	switch (rrtype)
	{
		case DNS_RRTYPE_SOA:		id = ((MYDNS_SOA *)rr)->id; break;
		case DNS_RRTYPE_RR:		id = ((MYDNS_RR *)rr)->id; break;
		case DNS_RRTYPE_PTR:		id = ((MYDNS_PTR *)rr)->id; break;
	}
	if (rrdup(&t->an, rrtype, id) || rrdup(&t->ns, rrtype, id) || rrdup(&t->ar, rrtype, id))
		return;

	if (!(new = malloc(sizeof(RR))))
		Err("malloc");
	new->rrtype = rrtype;
	switch (new->rrtype)
	{
		case DNS_RRTYPE_SOA:
			new->rr = mydns_soa_dup((MYDNS_SOA *)rr, 0);
			break;
		case DNS_RRTYPE_RR:
			new->rr = mydns_rr_dup((MYDNS_RR *)rr, 0);
			/* Save address info for ordering */
			if (((MYDNS_RR *)rr)->type == DNS_T_A || ((MYDNS_RR *)rr)->type == DNS_T_AAAA)
			{
				list->addresses++;
				if (((MYDNS_RR *)rr)->aux > list->highest_addr_aux)
					list->highest_addr_aux = ((MYDNS_RR *)rr)->aux;
			}
			break;
		case DNS_RRTYPE_PTR:	
			new->rr = mydns_ptr_dup((MYDNS_PTR *)rr, 0);
			break;
	}
	new->id = id;
	new->offset = 0;
	new->sort = 0;
	strncpy(new->name, name, sizeof(new->name)-1);
	new->next = NULL;
	if (!list->head)
		list->head = list->tail = new;
	else
	{
		list->tail->next = new;
		list->tail = new;
	}
	list->size++;
}
/*--- rrlist_add() ------------------------------------------------------------------------------*/

/* vi:set ts=3: */
